use std::time::Duration;

use async_listen::{error_hint, ListenExt};
use async_std::net::{TcpListener, TcpStream};

use honeybee::prelude::*;

use super::stream::UserStream;

pub struct UserListener {
    addr: Option<Addr<Self>>,
    listen_port: u16,
}

impl UserListener {
    pub fn new(listen_port: u16) -> Self {
        Self {
            addr: None,
            listen_port,
        }
    }
}

#[async_trait::async_trait]
impl Actor for UserListener {
    fn name(&self) -> &str {
        "UserListener"
    }

    async fn started(&mut self, ctx: &mut Context<Self>) -> honeybee::Result<()> {
        info!("{}:{} started", self.name(), ctx.actor_id());

        self.addr = Some(ctx.address());
        let listener = Box::new(
            TcpListener::bind(("0.0.0.0", self.listen_port))
                .await
                .unwrap(),
        );
        ctx.add_stream(
            Box::leak(listener)
                .incoming()
                .log_warnings(|err| {
                    error!(
                        "Accept User error: {}. Sleeping 0.5s. {}",
                        err,
                        error_hint(err)
                    )
                })
                .handle_errors(Duration::from_millis(500)),
        );
        Ok(())
    }
}

#[async_trait::async_trait]
impl StreamHandler<TcpStream> for UserListener {
    async fn handle(&mut self, _ctx: &mut Context<Self>, stream: TcpStream) {
        let _ = UserStream::new(stream).start().await;
    }

    async fn finished(&mut self, ctx: &mut Context<Self>) {
        info!("UserListener stoped");
        let _ = ctx.stop(None);
    }
}
